package com.qf.air.search.service.impl;

import com.qf.air.search.service.AirSearchService;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

@Service
public class AirSearchServiceImpl implements AirSearchService {

    @Autowired
    private RestHighLevelClient restHighLevelClient;

    @Override
    public Long findAirCount(Map map) throws IOException {
        //1. 创建SearchRequest
        SearchRequest request = new SearchRequest();
        //2. 设置索引信息
        request.indices("air");
        //3. 设置查询条件
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
        //3.1 设置查询区域districtId，
        Integer districtId = (Integer) map.get("districtId");
        if(districtId != null && districtId != 0){
            boolQuery.must(QueryBuilders.termQuery("districtId",districtId));
        }
        //3.2 设置监测站monitorStation
        String monitoringStation = (String) map.get("monitoringStation");
        if(!StringUtils.isEmpty(monitoringStation)){
            boolQuery.must(QueryBuilders.matchQuery("monitoringStation",monitoringStation));
        }
        //3.3 检测时间startTime
        Object startTime = map.get("startTime");
        if(startTime != null){
            boolQuery.must(QueryBuilders.rangeQuery("monitorTime").gte(startTime));
        }
        //3.4 检测时间endTime
        Object endTime = map.get("endTime");
        if(endTime != null){
            boolQuery.must(QueryBuilders.rangeQuery("monitorTime").lte(endTime));
        }
        sourceBuilder.query(boolQuery);
        request.source(sourceBuilder);

        //4. 将Request发送给Elasticsearch获取Resp返回结果
        SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT);

        //5. 获取到数据的总条数封装到VO的count里
        Long count = response.getHits().getTotalHits().value;

        //6. 返回数据总条数
        return count;
    }

    @Override
    public List<Map<String, Object>> findAirData(Map map) throws IOException {
        //1. 创建SearchRequest
        SearchRequest request = new SearchRequest();
        //2. 设置索引信息
        request.indices("air");
        //3. 设置查询条件
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
        //3.1 设置查询区域districtId，
        Integer districtId = (Integer) map.get("districtId");
        if(districtId != null && districtId != 0){
            boolQuery.must(QueryBuilders.termQuery("districtId",districtId));
        }
        //3.2 设置监测站monitorStation
        String monitoringStation = (String) map.get("monitoringStation");
        if(!StringUtils.isEmpty(monitoringStation)){
            boolQuery.must(QueryBuilders.matchQuery("monitoringStation",monitoringStation));
        }
        //3.3 检测时间startTime
        Object startTime = map.get("startTime");
        if(startTime != null){
            boolQuery.must(QueryBuilders.rangeQuery("monitorTime").gte(startTime));
        }
        //3.4 检测时间endTime
        Object endTime = map.get("endTime");
        if(endTime != null){
            boolQuery.must(QueryBuilders.rangeQuery("monitorTime").lte(endTime));
        }

        //4. 设置分页信息
        Integer page = (Integer) map.get("page");
        Integer rows = (Integer) map.get("rows");
        sourceBuilder.from((page - 1 ) * rows);
        sourceBuilder.size(rows);

        //5. 高亮信息（monitorStation的字段）
        HighlightBuilder highlightBuilder = new HighlightBuilder();
        highlightBuilder.fragmentSize(10);
        highlightBuilder.preTags("<span style='color:red;'>");
        highlightBuilder.postTags("</span>");
        highlightBuilder.field("monitoringStation");
        sourceBuilder.highlighter(highlightBuilder);

        sourceBuilder.query(boolQuery);
        request.source(sourceBuilder);

        //6. 将Request发送给Elasticsearch获取Resp返回结果
        SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT);

        //7. 获取到具体的数据(高亮显示),封装到VO的data里
        List<Map<String,Object>> data = new ArrayList<>();
        for (SearchHit hit : response.getHits().getHits()) {
            Map<String, Object> air = hit.getSourceAsMap();
            // 获取高亮显示的字段
            HighlightField highlightField = hit.getHighlightFields().get("monitoringStation");
            if(highlightField != null){
                air.put("monitoringStation",highlightField.getFragments()[0].toString());
            }
            // 添加到list
            data.add(air);
        }

        //8. 返回
        return data;
    }

    @Override
    public void add(Map map) throws IOException {
        //1. index,索引名和id
        IndexRequest indexRequest = new IndexRequest("air");
        indexRequest.id(map.get("id") + "");

        //2. source
        indexRequest.source(map);

        //3. index(request)
        IndexResponse resp = restHighLevelClient.index(indexRequest, RequestOptions.DEFAULT);

        //4. 判断添加是否成功
        if(!resp.getResult().toString().equalsIgnoreCase("created")){
            throw new RuntimeException("【搜索模块】 添加数据到Air索引失败 map =" + map);
        }
    }

}
